﻿using System;
using System.Linq.Expressions;
using Glue.Internals;
using GlueTests.Builders;
using Xunit;

namespace GlueTests.PropertyFactoryTests
{
    public class When_creating_properties_from_simplified_nesting
    {
        private readonly IObjectMember propertyOfCity;
        private readonly IObjectMember fieldOfId;
        private readonly IObjectMember methodOfZip;

        public class Person { public Address Address { get; set; } }
        public class Address
        {
            public int IdAsField;
            public String CityAsProperty { get; set; }
            public String ZipCodeAsMethod() { return "TheZipCode"; }
        }
        
        public When_creating_properties_from_simplified_nesting()
        {
            var factory = new ObjectMemberFactoryBuilder().Build();
            Expression<Func<Person, object>> expressionOfProperty = x => x.Address.CityAsProperty;
            propertyOfCity = factory.CreateObjectMember(expressionOfProperty);

            Expression<Func<Person, object>> expressionOfId = x => x.Address.IdAsField;
            fieldOfId = factory.CreateObjectMember(expressionOfId);

            Expression<Func<Person, object>> expressionOfZip = x => x.Address.ZipCodeAsMethod();
            methodOfZip = factory.CreateObjectMember(expressionOfZip);
        }

        [Fact]
        public void Should_return_when_property()
        {
            var person = new Person {Address = new Address {CityAsProperty = "TheCity"}};
            var city = (String)propertyOfCity.InvokeGet(person);
            Assert.Equal("TheCity",city);
        }

        [Fact]
        public void Should_set_when_property()
        {
            var newCityName = "NewCityName";
            var person = new Person { Address = new Address { CityAsProperty = "" } };
            propertyOfCity.InvokeSet(person,newCityName);
            Assert.Equal(newCityName, person.Address.CityAsProperty);
        }

        [Fact]
        public void Should_return_when_field()
        {
            var person = new Person {Address = new Address {IdAsField = 3} };
            var id = (int)fieldOfId.InvokeGet(person);
            Assert.Equal(3, id);
        }

        [Fact]
        public void Should_set_when_field()
        {
            var person = new Person { Address = new Address { IdAsField = 0} };
            fieldOfId.InvokeSet(person, 33);
            Assert.Equal(33, person.Address.IdAsField);
        }

        [Fact]
        public void Should_return_when_method()
        {
            var person = new Person { Address = new Address()};
            var zip = (string)methodOfZip.InvokeGet(person);
            Assert.Equal("TheZipCode", zip);
        }

        [Fact]
        public void Should_not_be_able_to_set_when_method()
        {
            Assert.False(methodOfZip.CanSetValues);
        }
    }
}
